home *** CD-ROM | disk | FTP | other *** search
Text File | 1997-04-25 | 11.8 KB | 340 lines | [TEXT/3PRM] |
- module Turing
-
- /* A Turing machine interpreter and programming environment.
- This program requires the 0.8 I/O library.
- Run the program using the "No Console" option (Application options).
- */
-
- import StdInt, StdString, StdBool, StdFile, StdTuple
- import deltaSystem, deltaFileSelect, deltaEventIO, deltaIOSystem, deltaMenu, deltaWindow, deltaTimer
- import tm, showtm, tmdialog, tmfile, Help
-
- WdCorner :== (0, 0)
- TWdCorner :== (100,210)
- WindowMin :== (50, 50)
- WindowInit :== (500,265)
- TapeWdMin :== (50, 50)
- TapeWdInit :== (400,60)
- WindowPSize :== ((0,0), (MaxX, 265))
- TapeWdPSize :== ((0,0), (MaxX, 92))
-
- Horbar :== ScrollBar (Thumb 0) (Scroll 24)
- Verbar :== ScrollBar (Thumb 0) (Scroll 8)
-
- Speed1 :== TicksPerSecond / 3
- Speed2 :== TicksPerSecond / 6
- Speed3 :== TicksPerSecond / 12
- Speed4 :== TicksPerSecond / 20
- Speed5 :== 0
-
- Start :: *World -> *World
- Start world
- # (events,world) = OpenEvents world
- (files, world) = openfiles world
- (aboutdialog,files) = MakeAboutDialog "Turing" HelpFile files Help
- progstate0 = NewTuring files
- about = DialogSystem [aboutdialog]
- (progstateN,events) = StartIO [about, menu, window, timer] progstate0 [] events
- files = progstateN.disk
- world = closefiles files world
- world = CloseEvents events world
- = world
- where
- menu = MenuSystem [file, machine]
- file = PullDownMenu FileMenuId "File" Able
- [ MenuItem NewItemId "New" (Key 'N') Able DoNew
- , MenuItem OpenItemId "Open..." (Key 'O') Able DoOpen
- , MenuItem SaveItemId "Save" (Key 'S') Unable DoSave
- , MenuItem SvAsItemId "Save As..." NoKey Able DoSaveAs
- , MenuSeparator
- , MenuItem HelpItemId "Help..." (Key 'H') Able Help
- , MenuSeparator
- , MenuItem QuitItemId "Quit" (Key 'Q') Able DoQuit
- ]
- machine = PullDownMenu MachineMenuId "Machine" Able
- [ MenuItem StepItemId "Step" (Key 'T') Unable DoStep
- , MenuItem RunItemId "Run" (Key 'R') Unable DoRun
- , MenuItem HaltItemId "Continue" (Key '.') Unable DoContinue
- , MenuSeparator
- , SubMenuItem DelayItemId "Speed" Able [delay]
- ]
- delay = MenuRadioItems NormId
- [ MenuRadioItem VerSId "Very Slow" (Key '1') Able (SetDelay Speed1)
- , MenuRadioItem SlowId "Slow" (Key '2') Able (SetDelay Speed2)
- , MenuRadioItem NormId "Normal" (Key '3') Able (SetDelay Speed3)
- , MenuRadioItem FastId "Fast" (Key '4') Able (SetDelay Speed4)
- , MenuRadioItem VerFId "Very Fast" (Key '5') Able (SetDelay Speed5)
- ]
-
- window = WindowSystem [trswd, tapewd]
- trswd = ScrollWindow WindowID WdCorner "Turing Machine" Horbar Verbar
- WindowPSize WindowMin WindowInit UpdateWindow
- [ Mouse Able EditTransitions
- , GoAway DoQuit
- ]
- tapewd = ScrollWindow TapeWdID TWdCorner "Tape" Horbar Verbar
- TapeWdPSize TapeWdMin TapeWdInit UpdateTapeWd
- [ Mouse Able EditTape
- , GoAway DoQuit
- ]
-
- timer = TimerSystem [Timer TimerID Unable Speed3 TimerStep]
-
- NewTuring :: Files -> Tm
- NewTuring files
- = { tmstate = { turing = { transitions = []
- , tape = { content = ""
- , head = 0
- }
- , state = ""
- }
- , transition = 0
- , command = None
- }
- , name = ""
- , delay = Speed3
- , disk = files
- , saved = True
- }
-
-
- // Open a new empty Turing machine.
- DoNew :: Tm (IOState Tm) -> (Tm,IOState Tm)
- DoNew tm=:{delay,disk,saved} io
- | saved = MakeNewTuring tm io
- # (sure,tm,io) = SaveBeforeClose "opening a new Turing machine" tm io
- | sure = MakeNewTuring tm io
- | otherwise = (tm,io)
-
- MakeNewTuring :: Tm (IOState Tm) -> (Tm,IOState Tm)
- MakeNewTuring {delay,disk} io
- # io = DrawInWindow TapeWdID [ShowTape inittape] io
- io = DrawInWindow WindowID [ShowTransitions [] ""] io
- io = ChangeWindowTitle WindowID "Turing Machine" io
- io = DisableMenuItems [SaveItemId,StepItemId,RunItemId,HaltItemId] io
- = ({ tmstate = { turing = { transitions = []
- , tape = inittape
- , state = ""
- }
- , transition = 0
- , command = None
- }
- , name = ""
- , delay = delay
- , disk = disk
- , saved = True
- }
- , io
- )
- where
- inittape = {content="",head=0}
-
- // Save the Turing machine.
- DoSave :: Tm (IOState Tm) -> (Tm,IOState Tm)
- DoSave tm=:{tmstate={turing},name,disk} io
- # (success,disk) = WriteTuringToFile turing name disk
- | success = ( {tm & disk=disk,saved=True}
- , DisableMenuItems [SaveItemId] io
- )
- | otherwise = Alert "The Turing machine has not been saved." "The file could not be opened." {tm & disk=disk} io
-
-
- DoSaveAs :: Tm (IOState Tm) -> (Tm,IOState Tm)
- DoSaveAs tm=:{name} io
- # (result,fname,tm=:{tmstate={turing},disk},io)
- = SelectOutputFile "Save T.M. As:" (RemovePath name) tm io
- | not result = (tm, io)
- | RemovePath fname==HelpFile = Alert "The Turing machine cannot be saved to" ("the help file \'"+++HelpFile+++"\'.") tm io
- # (success,disk) = WriteTuringToFile turing fname disk
- | not success = Alert "The Turing machine has not been saved." "The file could not be opened." {tm & disk=disk} io
- # io = ChangeWindowTitle WindowID (RemovePath fname) io
- io = DisableMenuItems [SaveItemId] io
- | otherwise = ({tm & name=fname,disk=disk,saved=True},io)
-
- // Load a Turing machine from a file.
- DoOpen :: Tm (IOState Tm) -> (Tm,IOState Tm)
- DoOpen tm=:{saved} io
- | saved = EvtOpenTuring tm io
- # (sure,tm,io) = SaveBeforeClose "opening an other Turing machine" tm io
- | sure = EvtOpenTuring tm io
- | otherwise = (tm,io)
- where
- EvtOpenTuring :: Tm (IOState Tm) -> (Tm,IOState Tm)
- EvtOpenTuring tm io
- # (ok,filename,tm,io) = SelectInputFile tm io
- | ok = OpenTuring filename tm io
- | otherwise = (tm,io)
- where
- OpenTuring :: String Tm (IOState Tm) -> (Tm,IOState Tm)
- OpenTuring name tm=:{delay,disk} io
- | fname==HelpFile = Alert ("The help file"+++fstring) "cannot be opened as a T.M." tm io
- # (status,turing,disk)
- = ReadTuring name disk
- | status==0 = ({tm & tmstate={turing=turing,transition=0,command=None},name=name,disk=disk,saved=True},update)
- with
- update = ChangeIOState
- [ EnableMenuItems [RunItemId,StepItemId,HaltItemId]
- , DrawInWindow TapeWdID [ShowTape turing.tape]
- , DrawInWindow WindowID [ShowTransitions turing.transitions turing.state]
- , ChangeWindowTitle WindowID (RemovePath name)
- , DisableMenuItems [SaveItemId]
- ] io
- | status> 0 = Alert ("Parse error in line "+++toString status) ("of file"+++fstring+++".") {tm & disk=disk} io
- | status==(-1) = Alert "Unexpected end of file" (fstring+++".") {tm & disk=disk} io
- | otherwise = Alert ("The file"+++fstring) "could not be opened." {tm & disk=disk} io
- where
- fname = RemovePath name
- fstring = " \'"+++fname+++"\'"
-
-
- // The Help command.
- Help :: Tm (IOState Tm) -> (Tm,IOState Tm)
- Help tm=:{disk} io
- # (disk,io) = ShowHelp HelpFile disk io
- = ({tm & disk=disk},io)
-
-
- // Let the Turing machine do one step (transition).
- DoStep :: Tm (IOState Tm) -> (Tm,IOState Tm)
- DoStep tm=:{tmstate=tmstate=:{turing={tape={head},state},transition}} io
- | state=="halt" || state=="error"
- = (tm,io)
- # tmstate = Step tmstate
- tm = {tm & tmstate=tmstate}
- (newtrn,newstate,newcom)
- = (\{turing,transition,command}->(transition,turing.state,command)) tmstate
- io = DrawInWindow WindowID [ShowTransition transition newtrn,ShowNextState newstate] io
- io = DrawInWindow TapeWdID [ShowNewTape newcom head] io
- io = StepChangeMenus newstate io
- | otherwise
- = ({tm & tmstate=tmstate},io)
- where
- StepChangeMenus :: String (IOState Tm) -> (IOState Tm)
- StepChangeMenus state io
- | state<>"halt" && state<>"error" = io
- | otherwise = DisableMenuItems [StepItemId,HaltItemId] io
-
-
- // Let the T.M. run until the haltstate is reached.
- DoRun :: Tm (IOState Tm) -> (Tm,IOState Tm)
- DoRun tm=:{tmstate={turing}} io
- # io = DisableMouse TapeWdID io
- io = DisableMouse WindowID io
- io = EnableMenuItems [HaltItemId] io
- io = ChangeMenuItemTitles [(HaltItemId,"Halt")] io
- io = ChangeMenuItemFunctions [(HaltItemId,DoHalt)] io
- io = DisableMenuItems [StepItemId, RunItemId] io
- io = DisableMenus [FileMenuId] io
- io = DrawInWindow TapeWdID [EraseError] io
- io = EnableTimer TimerID io
- = ({tm & tmstate={tm.tmstate & turing={turing & state="S"}}},io)
-
-
- // Halt a running T.M.
- DoHalt :: Tm (IOState Tm) -> (Tm,IOState Tm)
- DoHalt tm io
- # io = EnableMouse TapeWdID io
- io = EnableMouse WindowID io
- io = ChangeMenuItemTitles [(HaltItemId,"Continue")] io
- io = ChangeMenuItemFunctions [(HaltItemId,DoContinue)] io
- io = EnableMenuItems [StepItemId, RunItemId] io
- io = EnableMenus [FileMenuId] io
- io = DisableTimer TimerID io
- = (tm,io)
-
- // Continue a halted T.M.
- DoContinue :: Tm (IOState Tm) -> (Tm,IOState Tm)
- DoContinue tm io
- # io = DisableMouse TapeWdID io
- io = DisableMouse WindowID io
- io = ChangeMenuItemTitles [(HaltItemId,"Halt")] io
- io = ChangeMenuItemFunctions [(HaltItemId,DoHalt)] io
- io = DisableMenuItems [StepItemId, RunItemId] io
- io = DisableMenus [FileMenuId] io
- io = EnableTimer TimerID io
- = (tm,io)
-
- // Set the speed (delay) of a (possibly running) T.M.
- SetDelay :: Int Tm (IOState Tm) -> (Tm,IOState Tm)
- SetDelay delay tm io
- = ({tm & delay=delay},SetTimerInterval TimerID delay io)
-
-
- // Quit the program.
- DoQuit :: Tm (IOState Tm) -> (Tm,IOState Tm)
- DoQuit tm=:{saved} io
- | saved = (tm, QuitIO io)
- # (sure,tm,io) = SaveBeforeClose "quitting" tm io
- | sure = (tm, QuitIO io)
- | otherwise = (tm, io)
-
-
- // When a mouseclick occurs the T.M. can be edited.
- EditTransitions :: MouseState Tm (IOState Tm) -> (Tm,IOState Tm)
- EditTransitions (mpos,ButtonDown,_) tm=:{tmstate={turing={transitions}}} io
- | ontrans = AlterTransition transnr tm io
- | onstate = AlterState tm io
- | otherwise = (tm,io)
- where
- (nr,ontrans,onstate) = ClickedInWindow mpos
- lasttrans = NrOfTransitions transitions
- transnr = if (nr>lasttrans) lasttrans nr
- EditTransitions _ tm io = (tm,io)
-
- EditTape :: MouseState Tm (IOState Tm) -> (Tm,IOState Tm)
- EditTape (mpos,ButtonDown,CommandOnly) tm=:{tmstate={turing}} io
- | not ontape = (tm,io)
- # tape = MoveHead newpos turing.tape
- (((left,_),(right,_)),io) = WindowGetFrame TapeWdID io
- io = DrawInWindow TapeWdID [ShowHeadMove {tape & head=oldpos} newpos left right] io
- | otherwise = ({tm & tmstate={tm.tmstate & turing={turing & tape=tape}}},io)
- where
- oldpos = turing.tape.head
- (newpos,ontape) = ClickedInTapeWd mpos
- EditTape (mpos,ButtonDown,_) tm=:{tmstate={turing}} io
- | ontape = AlterCell (min nr (NrOfCells turing.tape.content)) tm io
- | otherwise = (tm,io)
- where
- (nr,ontape) = ClickedInTapeWd mpos
- EditTape _ tm io = (tm,io)
-
-
- // The window update and activate functions.
- UpdateWindow :: UpdateArea Tm -> (Tm, [DrawFunction])
- UpdateWindow update_area tm=:{tmstate={turing={transitions,state},transition}}
- = ( tm
- , [ SetTuringFont
- , ShowTransitions transitions state
- , ShowTransition transition transition
- ]
- )
-
- UpdateTapeWd :: UpdateArea Tm -> (Tm, [DrawFunction])
- UpdateTapeWd [((start,_),(end,_)):areas] tm=:{tmstate={turing={tape}}}
- # (tm,rest) = UpdateTapeWd areas tm
- = ( tm
- , [ SetTuringFont
- , ShowTapePart tape start end
- : rest
- ]
- )
- UpdateTapeWd _ tm
- = (tm,[])
-
-
- // The step function for the Timer device (used by the Run command).
- TimerStep :: TimerState Tm (IOState Tm) -> (Tm,IOState Tm)
- TimerStep times tm=:{tmstate={turing={state}}} io
- | state<>"halt" && state<>"error"
- = DoStep tm io
- # io = DisableTimer TimerID io
- io = EnableMouse TapeWdID io
- io = EnableMouse WindowID io
- io = ChangeMenuItemTitles [(HaltItemId,"Continue")] io
- io = ChangeMenuItemFunctions [(HaltItemId,DoContinue)] io
- io = DisableMenuItems [HaltItemId] io
- io = EnableMenuItems [RunItemId] io
- io = EnableMenus [FileMenuId] io
- | otherwise
- = (tm,io)
-